
#include <stdarg.h>
#include "commands.h"

//---------------------------------------------------------------------------

// ############# Taken from termy's sapp###
void (*cPrint)(int r,const char *text,...) = (void(*)(int,const char*,...))0x004b3800;
//void ( __cdecl *c_ExecuteCommand)(const char *cmd) = ( void(__cdecl*)(const char*) ) 0x0047EA20;


// ********
//Not taken from termy's sapp, only implemented as similar to it.


bool LoadCommandsFromFile(string filename, vector<playerindex> players)
{
	filename = Manager()->save_dir + filename;
	ifstream file;
	file.open(filename.c_str());
	if (file.rdstate() != 0) {
		file.close();
		cPrint(0, "bad file");
		return false;
	}
	vector<string> lines;
	char buff[320];
	while(1)
	{
		file.getline(buff, 300);
		lines.push_back(string(buff));
		if (file.rdstate() != 0) {
			break;
		}
	}
	file.close();

	string newcmd;
	for (size_t i = 0; i < lines.size(); i++) {
		if(players.size()>0)
		{
			for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end();pl++)
			{
    			newcmd = FormatCmd(lines[i], (*pl));

				cPrint(0, "Doing filecmd %s", newcmd.c_str());
				if(CustmCmd(newcmd.c_str()) == CMDNOMATCH)
					Server()->ExecCmd(newcmd.c_str());
			}
		} else
		{
			newcmd = lines[i];
			cPrint(0, "Doing filecmd %s", newcmd.c_str());

			if(Server()->DoCustomCommand(newcmd.c_str()) == CMDNOMATCH)
				Server()->ExecCmd(newcmd.c_str());
		}
	}
	return true;
}

template<typename T>
void ReplaceAll(string& str, string find, T replace)
{
	stringstream ss;
	ss << replace;

	size_t pos = 0;
	while(1)
	{
		pos = str.find(find, pos);
		if (pos==string.npos)
			break;
		str.replace(pos, find.size(), ss.str());
	}
}

// Player and Target may be -1 if it wasn't specified. Beware of that!
string FormatCmd(string cmd, playerindex pl_ind, playerindex target)
{
	if(Server()->IsOn(pl_ind))
	{
		playerindex revindex = IndtoReverse(pl_ind);

		PlayerInfo* playerinfo = Manager()->GetPlayerInfo(pl_ind);
		Static_Player* player = Server()->GetPlayer(pl_ind);

		ReplaceAll(cmd, "%I", pl_ind+1);
		ReplaceAll(cmd, "%R", IndtoReverse(pl_ind));
		ReplaceAll(cmd, "%N", Server()->GetPlayerName(pl_ind));
		ReplaceAll(cmd, "%T", player->Team);
		ReplaceAll(cmd, "%B", playerinfo->botdetects);
		ReplaceAll(cmd, "%A", playerinfo->admin_powers);
		if(Server()->IsSpawned(pl_ind))
		{
		ReplaceAll(cmd, "%H", Server()->GetBiped(pl_ind)->Health);
		ReplaceAll(cmd, "%S", Server()->GetBiped(pl_ind)->Shield1);
		ReplaceAll(cmd, "%C", CoordToStr(Server()->GetBiped(pl_ind)->World));
		AWeapon* weap = Server()->GetWeapon(pl_ind);
		if(weap)
			ReplaceAll(cmd, "%M", Server()->GetWeapon(pl_ind)->BulletCountInRemainingClips);
		ReplaceAll(cmd, "%K", player->KillsCount);
		ReplaceAll(cmd, "%L", Manager()->teleport.ClosestLoc(Server()->GetBiped(pl_ind)->World));
		}
	}
	if(Server()->IsOn(target))
	{ // repeat, but Lower Case.
		playerindex revindex = IndtoReverse(target);

		PlayerInfo* playerinfo = Manager()->GetPlayerInfo(target);
		Static_Player* player = Server()->GetPlayer(target);

		ReplaceAll(cmd, "%i", target+1);
		ReplaceAll(cmd, "%r", IndtoReverse(target));
		ReplaceAll(cmd, "%n", Server()->GetPlayerName(target));
		ReplaceAll(cmd, "%t", player->Team);
		ReplaceAll(cmd, "%b", playerinfo->botdetects);
		ReplaceAll(cmd, "%a", playerinfo->admin_powers);
		if(Server()->IsSpawned(target))
		{
		ReplaceAll(cmd, "%h", Server()->GetBiped(target)->Health);
		ReplaceAll(cmd, "%s", Server()->GetBiped(target)->Shield1);
		ReplaceAll(cmd, "%c", CoordToStr(Server()->GetBiped(target)->World));
		AWeapon* weap = Server()->GetWeapon(target);
		if(weap)
			ReplaceAll(cmd, "%m", Server()->GetWeapon(target)->BulletCountInRemainingClips);
		else
			ReplaceAll(cmd, "%m", "(no weapon)");
		ReplaceAll(cmd, "%k", player->KillsCount);
		ReplaceAll(cmd, "%l", Manager()->teleport.ClosestLoc(Server()->GetBiped(target)->World));
		}
	}

	// maybe commands will be different whether they use rcon or not.
	return cmd;
}


// possible parameters:
// %p - PlayerMatch for any _ON_ players, either a String that can be either a NameMatch, or the sv_players index. (sv_players's number is actually the MachineList index)
//  - which fills in a vector<playerindex> with all matching player indices (Players index, not machine or sv_players)
vector<playerindex> StrToIndList(string str)
{
	// There's also an ability to get all players NOT matching - by prefixing it with !.
	// That will instead make a list of all Other players, that _are_ on. 
	// Unfortunately, this will indeed require you to use ? matching for someone whos name starts with !.
	bool inverse = false;

	if(str[0] == '!')
	{
		inverse = true;
		str = str.substr(1); // cut off the !
	}

	vector<playerindex> indices;	
	if(str.length() < 1)
		return indices;
	if(str.length() < 3) // only check sv_players index if it's 1 or 2 long. It can hardly be helped, but i want to keep it as non-greedy as possible (since a player Could have a number as a name)
	{
		if(isnumber(str))
		{
			playerindex pl_ind = atoi(str.c_str());
			if (pl_ind < 1 || pl_ind > 16)
				pl_ind = 0;
			pl_ind--;
			for(playerindex i=0; i<16; i++)
				if(Server()->IsOn(i) && Server()->GetPlayer(i)->MachineIndex == pl_ind)
					indices.push_back(i);
		}
	}

	// check nicknames. If there's a match, return that player Only.
	else if(Static_Player* pl = Manager()->GetPlayerByNickname(str))
		indices.push_back(pl->PlayerIndex);
	else
	{
		for(playerindex i=0; i<16; i++)
		{
			if(Server()->IsOn(i))
			{
				if(NameMatch(Server()->GetPlayer(i), str))
					indices.push_back(i);
			}
		}
	}

	if(inverse)
	{
		vector<playerindex> otherindices;
		for(playerindex i=0; i<16; i++)
		{
			for(playerindex j=0; j<indices.size(); j++)
				if(indices[j] == i)
					continue;
			otherindices.push_back(i);
		}
		return otherindices;
	}
	else
		return indices;
}
// %b - Boolean. (1, 0, true, false, <empty>) - fills in a TOGGLE type (i.e. can be true false, or -1 if nothing was specified there.)
toggle StrToBoolean(string str)
{
	if(str == "1" || str == "true" || str == "True" || str == "yes" || str == "Yes" || str == "on" || str == "On")
		return 1;
	else if (str == "0" || str == "false" || str == "False" || str == "no" || str == "No" || str == "off" || str == "Off")
		return 0;
	return -1;
}
// %t - Team (1,0, Blue, Red, <empty>) - fills in a TOGGLE type (i.e. can be true false, or -1 if nothing was specified there.)
toggle StrToTeam(string str)
{
	if(str == "1" || str == "blue" || str == "Blue" || str == "zombie" || str == "Zombie")
		return 1;
	else if (str == "0" || str == "red" || str == "Red" || str == "human" || str == "Human")
		return 0;
	return -1;
}
// %c - Coord (makes use of StrToCoord) - fills in a vect3, and if the coord was invalid, fills in BAD_LOC.
//   - it's okay to have spaces or w/e format, 
	// uses StrToCoord() from Teleport
// %s - string (excellent for performing sv_say!) Can have spaces only if surrounded by quotes.

// %i - integer (cool. :) )

// %f - float  (also cool. :) )

// %h - "CD Hash", but actually can be any namematch, player index, or nickname.
//  - fills in a vector<PlayerInfo*>
vector<PlayerInfo*> StrToInfoList(string str)
{
	vector<PlayerInfo*> indices;
	if(str.length() < 1)
		return indices;
	if(str.length() < 3) // only check sv_players index if it's 1 or 2 long. It can hardly be helped, but i want to keep it as non-greedy as possible (since a player Could have a number as a name)
	{
		if(isnumber(str))
		{
			playerindex pl_ind = atoi(str.c_str());
			if (pl_ind < 1 || pl_ind > 16)
				pl_ind = 0;
			pl_ind--;
			for(playerindex i=0; i<16; i++)
				if(Server()->IsOn(i) && Server()->GetPlayer(i)->MachineIndex == pl_ind)
					indices.push_back(Manager()->GetPlayerInfo(i));
			return indices;
		}
	}

	// check nicknames. If there's a match, return that player Only.
	if(PlayerInfo* pl = Manager()->GetInfoByNickname(str))
		return (indices.push_back(pl), indices);

	for(playerindex i=0; i<16; i++)
	{
		if(Server()->IsOn(i))
		{
			if(NameMatch(Server()->GetPlayer(i), str))
				indices.push_back(Manager()->GetPlayerInfo(i));
		}
	}
	return indices;
}


toggle Wait(ArgContainer cmd)
{	// wait <seconds> <then do this command>
	// create a thread that waits seconds*1000 milliseconds, then run the command.
	return CMDSUCC;
}

// TeamSwap command: default adminlvl 1
// Swaps a player's team, and then unit_kills them to force them over.
// Additional arg: bool ForcePastZombification
//	-for higher admin levels, it will additionally swap a player's Zombification team, to bypass that check.
toggle TeamSwap(ArgContainer cmd)
{
	if (cmd.argc > 1)
	{
		toggle team = StrToTeam(cmd[2]);
		vector<playerindex> players = StrToIndList(cmd[1]);
		for(vector<playerindex>::iterator ind=players.begin(); ind!=players.end(); ind++)
		{
			playerindex pl_ind=*ind;
			cPrint(0, "ts index: %d", pl_ind);
			if (pl_ind == -1){
				cPrint(0, "bad ind.");
				return CMDFAIL;
			}
			if (!Server()->IsOn(pl_ind)){
				cPrint(0,"not on.");
				return CMDFAIL;
			}
			Static_Player* pl = Server()->GetPlayer(pl_ind);
			Server()->SetTeam(pl_ind, (team==-1 ? !pl->Team : team));
			cPrint(0, "%s (%d) is now %s", Server()->GetPlayerName(pl_ind).c_str(), pl_ind, (pl->Team==BLUE?"Blue":"Red"));
			if(Server()->IsSpawned(pl_ind))
			{
				string command = FormatCmd("unit_kill (unit (list_get (players) %R))", pl_ind);
				Server()->ExecCmd(command.c_str());
			}
		}
		return CMDSUCC;
	}
	return CMDFAIL;
}

toggle Invinc(ArgContainer cmd)
{
	if (cmd.argc < 2)
		return CMDFAIL;
	vector<playerindex> players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		string commd = FormatCmd("unit_set_maximum_vitality (unit (list_get (players) %R )) 0 0", pl_ind);
		cPrint(0, commd.c_str());
		Server()->ExecCmd(commd.c_str());
	}
	return CMDSUCC;
}

toggle Health(ArgContainer cmd)
{
	if (cmd.argc < 2)
		return CMDFAIL;
	float health = -1;
	sscanf_s(cmd[2].c_str(), "%f", &health);
	vector<playerindex> players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		if(Server()->IsSpawned(pl_ind))
		{
			ABiped* mc = (ABiped*) Server()->GetBiped(pl_ind);
			if(health != -1)
				mc->Health = health / 100.0f;
			Server()->ExecCmd(("sv_say \"" + Server()->GetPlayerName(pl_ind) + " now has " + ToStr(mc->Health) + " health.\"").c_str());
		}
	}
	return CMDSUCC;
}

toggle UnInvinc(ArgContainer cmd)
{
	if (cmd.argc < 2)
		return CMDFAIL;
	vector<playerindex> players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		string commd = FormatCmd("unit_set_maximum_vitality (unit (list_get (players) %R )) 100 50",IndtoReverse(pl_ind));
		cPrint(0, commd.c_str());
		Server()->ExecCmd(commd.c_str());
	}
	return CMDSUCC;
}

toggle CmdFile(ArgContainer cmd)
{
	if (cmd.argc < 2)
		return CMDFAIL;

	vector<playerindex> players;

	if (cmd.argc >= 3)
		players = StrToIndList(cmd[2]);

	cPrint(0, "Loading file...");
	LoadCommandsFromFile(cmd[1], players);
	return CMDSUCC;
}

toggle CmdFileAdd(ArgContainer cmd)
{
	if (cmd.argc < 3)
		return CMDFAIL;
	FileAppend(cmd[1], cmd[2]);
	return CMDSUCC;
}


toggle KillCmd(ArgContainer cmd)
{
	if(cmd.argc<2)
		return CMDFAIL;
	string command;
	vector<playerindex>players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		if(Server()->IsSpawned(pl_ind))
		{
			string command = FormatCmd("unit_kill (unit (list_get (players) %R))", pl_ind);
			Server()->ExecCmd(command.c_str());
		}
	}
	return CMDSUCC;
}

toggle Speed(ArgContainer cmd)
{
	if(cmd.argc<3)
		return CMDFAIL;
	float speed;
	if(sscanf(cmd[2].c_str(), "%f", &speed) < 1)
		return CMDFAIL;

	vector<playerindex>players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		Server()->GetPlayer(pl_ind)->VelocityMultiplier = speed;
	}
	return CMDSUCC;
}

toggle Ammo(ArgContainer cmd)
{
	if(cmd.argc<3)
		return CMDFAIL;
	unsigned short ammo=10;
	if(sscanf(cmd[2].c_str(), "%hu", &ammo) < 1)
		return CMDFAIL;

	vector<playerindex>players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		Server()->SetAmmo(pl_ind, ammo);
	}
	return CMDSUCC;
}

toggle Freeze(ArgContainer cmd)
{
	if(cmd.argc<2)
		return CMDFAIL;
	toggle freeze = StrToBoolean(cmd[2]);
	vector<playerindex>players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		if(Server()->IsSpawned(pl_ind))
		{
			ABiped* mc = (ABiped*) Server()->GetBiped(pl_ind);
			TOGGLE(mc->Frozen, freeze);
		}
	}
	return CMDSUCC;
}
// controls a player's admin level. ToDo: check against the player, since an admin must be adminlvl20 or greater to move other admins above 9. (or something like that)
toggle Admin(ArgContainer cmd)
{
	if(cmd.argc<2)
		return CMDFAIL;

	vector<playerindex> players = StrToIndList(cmd[1]);
	if(players.size()!= 1)
		return CMDFAIL;
	playerindex pl_ind = players[0];
	if (pl_ind == -1)
		return CMDFAIL;
	PlayerInfo* player = Manager()->GetPlayerInfo(pl_ind);
	if(player==NULL)
		return CMDFAIL;

	if(cmd.argc == 2)
	{
		cPrint(0, "Admin: %s, %d", Server()->GetPlayerName(pl_ind).c_str(), player->admin_powers);
		return CMDSUCC;
	}

	player->admin_powers = atoi(cmd[2].c_str());
	cPrint(0, "Admin: %s, %d", Server()->GetPlayerName(pl_ind).c_str(), player->admin_powers);
	return CMDSUCC;
}

toggle ChatBlock(ArgContainer cmd)
{
	if (cmd.argc < 2)
		return CMDFAIL;
	toggle block_chat = StrToBoolean(cmd[2]);
	vector<playerindex> players = StrToIndList(cmd[1]);
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		PlayerInfo* player = Manager()->GetPlayerInfo(pl_ind);
		if(player == NULL)
			continue;
		// Toggle chatblock for the player.
		player->can_chat = !((block_chat==-1) ? (player->can_chat) : block_chat);
		cPrint(0, "Player %d %s chat.", pl_ind, (player->can_chat ? "can" : "cannot"));
	}
	return CMDSUCC;
}

toggle Nickname(ArgContainer cmd)
{
	if(cmd.argc<3)
		return CMDFAIL;

	vector<playerindex>players = StrToIndList(cmd[1]);
	if(players.size() != 1)
		return CMDFAIL;
	for(vector<playerindex>::iterator pl=players.begin(); pl!=players.end(); pl++)
	{
		playerindex pl_ind=*pl;
		if (pl_ind == -1)
			return CMDFAIL;
		Manager()->AddNickname(pl_ind, cmd[2]);
		cPrint(0, "Nickname (%s) added for %s.", cmd[2].c_str(), Server()->GetPlayerName(pl_ind).c_str());
	}
	return CMDSUCC;
}

toggle Save(ArgContainer cmd)
{
	Manager()->SavePlayers();
	Manager()->teleport.Save();
	cPrint(0, "Saved (we hope).");
	return CMDSUCC;
}

toggle Load(ArgContainer cmd)
{
	Manager()->LoadPlayers();
	Manager()->teleport.Load();
	cPrint(0, "Loaded (we hope).");
	return CMDSUCC;
}

toggle PlayerList(ArgContainer cmd)
{
	char command[70];
	for(size_t i=0; i<16; i++)
	{
		if(Server()->IsOn(i))
		{
			sprintf_s(command, 70, "sv_say \"%2d: %s\"", Server()->GetPlayer(i)->MachineIndex, Server()->GetPlayerName(i).c_str());
			Server()->ExecCmd(command);
		}
	}
	return CMDSUCC;
}

toggle Debug(ArgContainer cmd)
{
	TOGGLE(Server()->debug, StrToBoolean(cmd[1]));
	cPrint(0, "Debug is now %s", (Server()->debug ? "on" : "off") );
	return CMDSUCC;
}
toggle AimSensitivity(ArgContainer cmd)
{
	if(cmd.argc>1)
	{
		sscanf(cmd[1].c_str(), "%f", &Manager()->aim_sensitivity);
	}
	cPrint(0, "Aim Sensitivity: %f", Manager()->aim_sensitivity);
	return CMDSUCC;
}
toggle BotDetect(ArgContainer cmd)
{
	TOGGLE(Manager()->botcheck, StrToBoolean(cmd[1]));
	cPrint(0, "Bot Detection is now %s", (Manager()->botcheck ? "on" : "off") );
	return CMDSUCC;
}
void InitCustomCommands()
{
	Server()->AddCustomCommand("teamswap", TeamSwap);
	Server()->AddCustomCommand("ts", TeamSwap);
	Server()->AddCustomCommand("teamswitch", TeamSwap);

	Server()->AddCustomCommand("teleport", Teleport);
	Server()->AddCustomCommand("tel", Teleport);
	Server()->AddCustomCommand("t", Teleport);
	Server()->AddCustomCommand("addtel", AddTel);
	Server()->AddCustomCommand("telrelative", TelRelative);
	Server()->AddCustomCommand("telrel", TelRelative);
	Server()->AddCustomCommand("jump", Jump);
	Server()->AddCustomCommand("j", Jump);

	Server()->AddCustomCommand("health", Health);
	Server()->AddCustomCommand("invinc", Invinc);
	Server()->AddCustomCommand("uninvinc", UnInvinc);
	Server()->AddCustomCommand("cmdfile", CmdFile);
	Server()->AddCustomCommand("cmdfileadd", CmdFileAdd);
	Server()->AddCustomCommand("kill", KillCmd);
	Server()->AddCustomCommand("k", KillCmd);
	Server()->AddCustomCommand("speed", Speed);
	Server()->AddCustomCommand("ammo", Ammo);
	Server()->AddCustomCommand("lag", Freeze);
	Server()->AddCustomCommand("freeze", Freeze);

	Server()->AddCustomCommand("admin", Admin);
	Server()->AddCustomCommand("chatblock", ChatBlock);
	Server()->AddCustomCommand("nickname", Nickname);
	
	Server()->AddCustomCommand("debug", Debug);
	Server()->AddCustomCommand("sensitivity", AimSensitivity);
	Server()->AddCustomCommand("botdetect", BotDetect);
	Server()->AddCustomCommand("save", Save);
	Server()->AddCustomCommand("loadapp", Load);
	Server()->AddCustomCommand("players", PlayerList);
	cPrint(0, "Custom Commands Initialized");
}
__declspec(dllexport) toggle CustmCmd(const char* CmdStr)
{
	add_log("custom command tried");
	//return CMDNOMATCH;
	//AnsiString command = "sv_note \"Custom Command: " + AnsiString(CmdStr) + " done by: \"";
	//ExecuteCommand(command.c_str());
	ArgContainer cmd(CmdStr);
	if(cmd.argc <1)
		return CMDNOMATCH;

	toggle check;
	if((check = Server()->DoCustomCommand(CmdStr)) != CMDNOMATCH)
		return check;

	if (cmd[0] == "zombie")
	{
		//Manager()->zombification = !Manager()->zombification;
		//cPrint(0, "Zombification %s.", (Manager()->zombification?"enabled":"disabled"));
		cPrint(0, "Zombification is faulty, and is disabled. (Wait for next release)");
		return CMDFAIL;
	}

	return CMDNOMATCH;

}

void sv_cmd(const char* CmdStr)
{	// In an ordinary sv_xxx command, replace any %I with the NameMatch in that place. And then execute the cmd.
	ArgContainer cmd(CmdStr);
	if(cmd.argc<2)
	{
		Server()->ExecCmd(CmdStr);
		return;
	}
	vector<playerindex> players;

	if(cmd[0] == "sv_kick" || cmd[0] == "sv_ban")
		if(cmd.argc>1)
			players = StrToIndList(cmd[1]);

	if(players.size()==0)
		Server()->ExecCmd(CmdStr);
	else
	{
		for(size_t i=0;i<players.size();i++)
		{
			cPrint(0, "Player: %d", players[i]);
			string command = cmd[0] + " " + ToStr(players[i]+1);
			Server()->ExecCmd(command.c_str());
		}
	}
}

// If the command / player is allowed, then SAPP is allowed to handle it (return TRUE). Else, return false, where it just goes to print the string.
// ALSO: it is possible that some commands WILL change the chat, perhaps to hide passwords, etc. If that happens, this will ALSO do an sv_NOTE to say the original chat.
bool ChatIntercept(wchar_t* thechat, Static_Player* player)
{
	add_log("chat intercepted");
	MachineInfo* machine = &Server()->machinelist[player->MachineIndex];
	PlayerInfo* pl = Manager()->GetPlayerInfo(machine->CDhash);
	string chat = WidetoString(wstring(thechat));

	if(chat.c_str()[0] == '/') // '/' is the cmd start delimiter, so it's a cmd.
	{ // A: check admin permissions for that person.
		if(CanDoCmd(chat.c_str()+1, pl->admin_powers))
		{
			Server()->ExecCmd("sv_say \"Cmd Successful.\"");
			cPrint(0, "Cmd (%s) successful. hash:%s.", chat.c_str()+1, machine->CDhash);
			if(Server()->DoCustomCommand(chat.c_str()+1) == CMDNOMATCH)
			{
				if(CustmCmd(chat.c_str()+1) == CMDNOMATCH)
					sv_cmd(chat.c_str()+1);
			}
		}else
		{
			Server()->ExecCmd("sv_say \"You don't have high enough admin priveleges.\"");
			//cPrint(0, "Cmd failed:%s", machine->CDhash);
		}
	}

	// clear the chat if the player cannot chat.
	if(!pl->can_chat)
	{
		cPrint(0, "[BLOCKED] %s: %s", WidetoString(wstring(player->Name)).c_str(), WidetoString(wstring(thechat)).c_str());
		thechat[0] = L'\0';
		thechat[1] = L'\0';
	}
	return pl->can_chat;
}

